﻿#ifndef _XML_H_
#define _XML_H_

#pragma once

#include "kernel/OgrePlatform.h"
#include "kernel/multibytestring.h"
#include <map>
#include <vector>
#include "kernel/string_def.h"
#include "kernel/Referenced.h"

class TiXmlDocument;
class TiXmlElement;

namespace FD
{
	namespace Kernel
	{
		/// <summary>
		/// 结点元素类
		/// 对各个结点元素的操作
		/// </summary>
		class XmlElement;

		typedef std::vector<XmlElement> XmlElementList;
		/// <summary>
		/// 文件类
		/// 对各种文件的操作
		/// </summary>
		class FD_Kernel_Export XmlDocument : public FD::Kernel::CReferenced
		{
			friend class XmlElement;
			typedef std::vector<FD::Kernel::XmlElement *> XMLRefList;
		public:
			enum enumXmlEncodingType
			{
				xmlEncodingUnknown,
				xmlEncodingUtf8,
				xmlEncodingLegacy,
				xmlEncodingDefault,
				xmlEncodingGB2312
			};
		public:
			/// <summary>
			/// 默认构造函数
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			XmlDocument();
			/// <summary>
			/// 构造函数
			/// </summary>
			/// <param name="strFilename">文件名</param>
			/// <param name="encodingType">编码类型</param>
			/// <returns></returns>
			XmlDocument(const String &strFilename, enumXmlEncodingType encodingType);
			/// <summary>
			/// 构造函数
			/// </summary>
			/// <param name="buffer">缓冲区</param>
			/// <param name="size">大小</param>
			/// <param name="encodingType">编码类型</param>
			/// <returns></returns>
			XmlDocument(String buffer, uint32 size, enumXmlEncodingType encodingType);
		public:
			/// <summary>
			/// 析构函数
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			virtual ~XmlDocument();
			/// <summary>
			/// 使用指定的根结点名称创建新的XML数据
			/// </summary>
			/// <param name="strRootName">XML数据根结点的名称</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool createXml(const String &strRootName);
			/// <summary>
			/// 使用指定的根结点名称创建新的XML数据
			/// </summary>
			/// <param name="strRootName">根节点名称</param>
			/// <param name="encodingType">编码类型</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool createXml(const String &strRootName, enumXmlEncodingType encodingType);
			/// <summary>
			/// 读取并解析XML文件
			/// </summary>
			/// <param name="encodingType">编码类型</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool loadFile(enumXmlEncodingType encodingType);
			/// <summary>
			/// 读取并解析XML文件
			/// </summary>
			/// <param name="strFilename">文件名</param>
			/// <param name="encodingType">类型</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool loadFile(const String &strFilename, enumXmlEncodingType encodingType);
			/// <summary>
			/// 读取并解析XML字符串
			/// </summary>
			/// <param name="strXmlString">XML字符串</param>、
			/// <param name="encodingType">编码类型</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool loadString(const String &strXmlString, enumXmlEncodingType encodingType);
			/// <summary>
			/// 将当前的XML数据转换为String
			/// </summary>
			/// <param name=""></param>
			/// <returns>XML字符串</returns>
			String toString(bool ConvertToGBK = false) const;
			/// <summary>
			/// 将当前的XML数据存储到文件
			/// </summary>
			/// <param name="iUnbuffered"></param>
			/// <returns>有返回值true，否则返回false</returns>
			bool saveFile(INT32 iUnbuffered) const;
			/// <summary>
			/// 将当前的XML数据存储到文件
			/// </summary>
			/// <param name="strFilename">文件名</param>
			/// <param name="iUnbuffered"></param>
			/// <returns>有返回值true，否则返回false</returns>
			bool saveFile(const String &strFilename, INT32 iUnbuffered) const;
			/// <summary>
			/// 判断当前对象是否已经读取了XML数据
			/// </summary>
			/// <param name=""></param>
			/// <returns>已经打开返回true，否则返回false</returns>
			bool isLoaded() const;
			/// <summary>
			/// 关闭当前打开的XML解析内容
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			void unload();
			/// <summary>
			/// 获取XML文档的根元素结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>根节点对象</returns>
			FD::Kernel::XmlElement getRoot();

			/// <summary>
			/// 获取XML文档的根元素结点
			/// </summary>
			/// <param name="rootElement">根结点对象</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getRoot( FD::Kernel::XmlElement &rootElement);
			/// <summary>
			/// 获取声明信息中的版本信息
			/// </summary>
			/// <param name=""></param>
			/// <returns>字符串形式的版本信息</returns>
			String getVersion()  const;
			/// <summary>
			/// 获取声明信息中的编码信息
			/// </summary>
			/// <param name=""></param>
			/// <returns>字符串形式的编码信息</returns>
			String getEncoding() const;
			/// <summary>
			/// 获取最后一条错误描述信息
			/// </summary>
			/// <param name=""></param>
			/// <returns>错误描述信息</returns>
			String getLastErrorDescript() const;
			/// <summary>
			/// 设置声明信息中的版本信息
			/// </summary>
			/// <param name=" strVersion">版本信息的值</param>
			/// <returns></returns>
			bool setVersion(const String &strVersion);

		private:
			/// <summary>
			/// 添加共享结点数据引用时触发的函数
			/// </summary>
			/// <param name="pSharedTiXmlNode">共享结点实体的指针</param>
			/// <param name="pShareNodeUser">共享结点使用者的指针</param>
			/// <returns></returns>
			void onAddShareReference(TiXmlElement *pSharedTiXmlNode, FD::Kernel::XmlElement *pShareNodeUser);
			/// <summary>
			/// 移除共享结点数据引用时触发的函数
			/// </summary>
			/// <param name="pSharedTiXmlNode">共享结点实体的指针</param>
			/// <param name="pShareNodeUser">共享结点使用者的指针</param>
			/// <returns></returns>
			void onRemoveShareReference(TiXmlElement *pSharedTiXmlNode, FD::Kernel::XmlElement *pShareNodeUser);
			/// <summary>
			/// 移除共享结点数据时触发的函数
			/// </summary>
			/// <param name="pRemoveNode">被移除的TiXml结点</param>
			/// <returns></returns>
			void onRemoveElement(TiXmlElement *pRemoveNode);
			/// <summary>
			/// 禁用赋值函数和拷贝构造函数
			/// </summary>
			/// <param name="other">参数列表</param>
			/// <returns></returns>
			XmlDocument(const XmlDocument &other);
			/// <summary>
			/// 重载=运算符
			/// </summary>
			/// <param name="other">右操作数</param>
			/// <returns></returns>
			XmlDocument &operator=(const XmlDocument &other);

			String convert(const char* pBuf)const;
		private:
			///TiXml的文档对象
			TiXmlDocument *m_pTixmlDoc;
			///记录TiXml结点对象引用的map
			std::map<TiXmlElement *, XMLRefList> m_mapRefs;
			///当前对象存储的XML文件名
			String m_strFileName;
		};
		/// <summary>
		/// XML元素结点类，例如：<mynode myatrri="this is my attribute">this is my value</mynode>
		/// 对各种结点的操作
		/// </summary>
		class FD_Kernel_Export XmlElement : public FD::Kernel::CReferenced
		{
			friend class XmlDocument;
		public:
			/// <summary>
			/// 默认构造函数
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			XmlElement();
			/// <summary>
			/// 构造函数
			/// </summary>
			/// <param name="strName">结点名称</param>
			/// <param name="strValue">结点值</param>
			/// <returns></returns>
			XmlElement(const String &strName, const String &strValue);
			/// <summary>
			/// 拷贝构造函数
			/// </summary>
			/// <param name="another">另一个结点对象</param>
			/// <returns></returns>
			XmlElement(const XmlElement &another);
		public:
			/// <summary>
			/// 析构函数
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			virtual ~XmlElement();
			/// <summary>
			/// 重载=运算符
			/// </summary>
			/// <param name="another">另一个结点对象</param>
			/// <returns></returns>
			FD::Kernel::XmlElement &operator=(const FD::Kernel::XmlElement &another);

			/// <summary>
			/// 使当前结点创建为一个有效的独立结点
			/// </summary>
			/// <param name="strName">结点名称</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool createElement(const String &strName);
			/// <summary>
			/// 使当前结点创建为一个有效的独立结点
			/// </summary>
			/// <param name="strName">结点名称</param>
			/// <param name="strValue">结点值</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool createElement(const String &strName, const String &strValue);
			/// <summary>
			/// 重置当前结点对象，重置后，当前结点对象将变得无效，需要重新进行初始化
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			void reset();
			/// <summary>
			/// 判断当前对象是否有效，有效的对象才能进行各项操作
			/// </summary>
			/// <param name=""></param>
			/// <returns></returns>
			bool isValid() const;
			/// <summary>
			/// 判断当前结点是否是以共享方式占用结点实体数据
			/// </summary>
			/// <param name=""></param>
			/// <returns>有返回值true，否则返回false</returns>
			bool isShareMode() const;
			/// <summary>
			/// 取得当前结点元素的名称
			/// </summary>
			/// <param name=""></param>
			/// <returns>结点元素名称</returns>
			String getName() const;
			/// <summary>
			/// 设置当前结点元素的名称
			/// </summary>
			/// <param name="strName">结点名称</param>
			/// <returns>成功返回true，否则返回false</returns>
			bool setName(const String &strName);
			/// <summary>
			/// 取得当前结点元素的值
			/// </summary>
			/// <param name=""></param>
			/// <returns>当前结点元素的值</returns>
			String getValueString() const;
			/// <summary>
			/// 设置当前结点元素的值
			/// </summary>
			/// <param name="strValue">结点值</param>
			/// <returns>当前结点元素的值</returns>
			bool setValue(const String &strValue);
			/// <summary>
			/// 取得当前结点元素指定属性的值
			/// </summary>
			/// <param name="strAttributeName">属性名</param>
			/// <returns>属性值</returns>
			String getAttributeString( const String &strAttributeName) const;
			/// <summary>
			/// 取得当前结点元素指定属性的值
			/// </summary>
			/// <param name="nAttributeIndex">索引</param>
			/// <param name="strAttributeName">属性名称</param>
			/// <param name="strAttributeValue">属性值</param>
			/// <returns>属性值</returns>
			bool getAttributeString( uint32 nAttributeIndex,
				String &strAttributeName,
				String &strAttributeValue) const;
			/// <summary>
			///取得当前结点元素属性的数量
			/// </summary>
			/// <param name=""></param>
			/// <returns>属性的数量</returns>
			uint32 getAttributeCount() const;
			/// <summary>
			///设置当前结点元素指定属性的值，当指定的属性名不存在时，则增加该属性
			/// </summary>
			/// <param name="strAttributeName">属性名称</param>
			/// <param name="strAttributeValue">属性值</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool setAttribute(const String &strAttributeName, const String &strAttributeValue);
			/// <summary>
			///设置当前结点元素指定属性的值，当指定的属性名不存在时，则增加该属性
			/// </summary>
			/// <param name="strAttributeName">属性名称</param>
			/// <param name="dbAttributeValue">实数型属性值</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool setAttribute(const String &strAttributeName, const double &dbAttributeValue);
			/// <summary>
			///设置当前结点元素指定属性的值，当指定的属性名不存在时，则增加该属性
			/// </summary>
			/// <param name="strAttributeName">属性名称</param>
			/// <param name="intAttributeValue">整型属性值</param>
			/// <returns>有返回值true，否则返回false</returns>
			bool setAttribute(const String &strAttributeName, const INT32 &intAttributeValue);
			/// <summary>
			///移除掉指定的属性
			/// </summary>
			/// <param name="strAttributeName">属性名称</param>
			/// <returns>移除了一个属性返回true，否则返回false</returns>
			bool removeAttribute(const String &strAttributeName);
			/// <summary>
			///移除掉所有的属性
			/// </summary>
			/// <param name=""></param>
			/// <returns>移除的属性个数</returns>
			uint32  removeAllAttribute();
			/// <summary>
			///判断当前结点是否是叶子结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>是叶子结点返回true，否则返回false</returns>
			bool isLeaf() const;
			/// <summary>
			///判断某结点是否是自己的子结点
			/// </summary>
			/// <param name="xmlElement">子结点</param>
			/// <returns>是子结点返回true，否则返回false</returns>
			bool isMyChild(const FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///判断当前结点是否是根结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>是根结点返回true，否则返回false</returns>
			bool isRoot() const;
			/// <summary>
			///获得当前结点的父结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>父节点对象</returns>
			FD::Kernel::XmlElement getParent();
			/// <summary>
			///获得当前结点的父结点
			/// </summary>
			/// <param name="xmlElement">父结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getParent( FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的孩子结点数量
			/// </summary>
			/// <param name=""></param>
			/// <returns>孩子结点的数量</returns>
			uint32 getChildCount() const;
			/// <summary>
			///获取当前结点的第一个指定名称的孩子结点，若没有指定名称就获取第一个孩子结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>子结点对象</returns>
			FD::Kernel::XmlElement getFirstChild();
			/// <summary>
			///获取当前结点的第一个指定名称的孩子结点，若没有指定名称就获取第一个孩子结点
			/// </summary>
			/// <param name="strChildName">子结点名称</param>
			/// <returns>子结点对象</returns>
			FD::Kernel::XmlElement getFirstChild(const String &strChildName);
			/// <summary>
			///获取当前结点的第一个指定名称的孩子结点，若没有指定名称就获取第一个孩子结点
			/// </summary>
			/// <param name="xmlElement">子结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getFirstChild( FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的第一个指定名称的孩子结点，若没有指定名称就获取第一个孩子结点
			/// </summary>
			/// <param name="strChildName">子结点名称</param>
			/// <param name="xmlElement">子结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getFirstChild(const String &strChildName,  FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的最后一个指定名称的孩子结点，若没有指定名称就获取最后一个孩子结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>子结点对象</returns>
			FD::Kernel::XmlElement getLastChild();
			/// <summary>
			///获取当前结点的最后一个指定名称的孩子结点，若没有指定名称就获取最后一个孩子结点
			/// </summary>
			/// <param name="strChildName">孩子结点名称</param>
			/// <returns>子结点对象</returns>
			FD::Kernel::XmlElement getLastChild(const String &strChildName);
			/// <summary>
			///获取当前结点的最后一个指定名称的孩子结点，若没有指定名称就获取最后一个孩子结点
			/// </summary>
			/// <param name="xmlElement">子结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getLastChild( FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的最后一个指定名称的孩子结点，若没有指定名称就获取最后一个孩子结点
			/// </summary>
			/// <param name="strChildName">子结点名称</param>
			/// <param name="xmlElement">子节点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getLastChild(const String &strChildName,  FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取指定序号的孩子结点
			/// </summary>
			/// <param name="nIndex">孩子结点的序号</param>
			/// <param name="xmlElement">子结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getChild(uint32 nIndex,  FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的下一个指定名称的兄弟结点，若没有指定名称就获取下一个兄弟结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>结点对象</returns>
			FD::Kernel::XmlElement getNextSibling();
			/// <summary>
			///获取当前结点的下一个指定名称的兄弟结点，若没有指定名称就获取下一个兄弟结点
			/// </summary>
			/// <param name="strSiblingName">兄弟结点的名称</param>
			/// <returns>结点对象</returns>
			FD::Kernel::XmlElement getNextSibling(const String &strSiblingName);
			/// <summary>
			///获取当前结点的下一个指定名称的兄弟结点，若没有指定名称就获取下一个兄弟结点
			/// </summary>
			/// <param name="xmlElement">兄弟结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getNextSibling( FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的下一个指定名称的兄弟结点，若没有指定名称就获取下一个兄弟结点
			/// </summary>
			/// <param name="strSiblingName">兄弟结点的名称</param>
			/// <param name="xmlElement">兄弟结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getNextSibling(const String &strSiblingName,  FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的上一个指定名称的兄弟结点，若没有指定名称就获取上一个兄弟结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>结点对象</returns>
			FD::Kernel::XmlElement getPrevSibling();
			/// <summary>
			///获取当前结点的上一个指定名称的兄弟结点，若没有指定名称就获取上一个兄弟结点
			/// </summary>
			/// <param name="strSiblingName">兄弟结点的名称</param>
			/// <returns>结点对象</returns>
			FD::Kernel::XmlElement getPrevSibling(const String &strSiblingName);
			/// <summary>
			///获取当前结点的前一个指定名称的兄弟结点，若没有指定名称就获取前一个兄弟结点
			/// </summary>
			/// <param name="xmlElement">兄弟结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getPrevSibling( FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的前一个指定名称的兄弟结点，若没有指定名称就获取前一个兄弟结点
			/// </summary>
			/// <param name="strSiblingName">兄弟结点的名称</param>
			/// <param name="xmlElement">兄弟结点</param>
			/// <returns>获取成功返回true，否则返回false</returns>
			bool getPrevSibling(const String &strSiblingName,  FD::Kernel::XmlElement &xmlElement);
			/// <summary>
			///获取当前结点的第几项注释内容
			/// </summary>
			/// <param name="nIndex">注释内容的序号</param>
			/// <returns>注释内容</returns>
			String getComment(uint32 nIndex = 0) const;
			/// <summary>
			///获取当前结点的第几项注释内容
			/// </summary>
			/// <param name="nIndex">注释内容的序号</param>
			/// <param name="strComment">注释内容</param>
			/// <returns>注释内容</returns>
			bool getComment(uint32 nIndex,  String &strComment) const;
			/// <summary>
			///获取当前结点的注释条数
			/// </summary>
			/// <param name=""></param>
			/// <returns>注释条数</returns>
			uint32 getCommentCount() const;
			/// <summary>
			///追加当前结点的注释内容
			/// </summary>
			/// <param name="strCommnetContent">注释的内容</param>
			/// <returns>添加的注释的序号</returns>
			uint32 appendComment(const String &strCommnetContent);
			/// <summary>
			///移除当前结点的第几项注释内容
			/// </summary>
			/// <param name="nIndex">注释内容的序号</param>
			/// <returns>移动指定序号的注释返回true，否则返回false</returns>
			bool removeComment(uint32 nIndex = 0);
			/// <summary>
			///移除当前结点的所有注释内容
			/// </summary>
			/// <param name=""></param>
			/// <returns>移除的注释条数</returns>
			uint32 removeAllComment();
			/// <summary>
			///为当前结点追加孩子结点
			/// </summary>
			/// <param name="appendElement">要增加孩子结点对象</param>
			/// <returns>操作成功返回true，否则返回false</returns>
			bool appendChild(const FD::Kernel::XmlElement &appendElement);

			bool appendChild(const String& name, const String& val);
			/// <summary>
			///在某个孩子结点的前方插入孩子结点
			/// </summary>
			/// <param name="addThis">要增加孩子结点对象</param>
			/// <param name="beforeThis">在该结点前插入</param>
			/// <returns>操作成功返回true，否则返回false</returns>
			bool insertChildBefore(const FD::Kernel::XmlElement &addThis,  FD::Kernel::XmlElement &beforeThis);
			/// <summary>
			///在某个孩子结点的后方插入孩子结点
			/// </summary>
			/// <param name="addThis">要增加孩子结点对象</param>
			/// <param name="afterThis">在该结点后插入</param>
			/// <returns>操作成功返回true，否则返回false</returns>
			bool insertChildAfter(const FD::Kernel::XmlElement &addThis,  FD::Kernel::XmlElement &afterThis);
			/// <summary>
			///移除指定的孩子结点
			/// </summary>
			/// <param name="removeElement">要移除的孩子结点对象</param>
			/// <returns>移除的孩子结点数目</returns>
			uint32 removeChild(const FD::Kernel::XmlElement &removeElement);
			/// <summary>
			///移除指定的孩子结点
			/// </summary>
			/// <param name="strElementName">要移除的孩子结点的名称</param>
			/// <returns>移除的孩子结点的数目</returns>
			uint32 removeChild(const String &strElementName);
			/// <summary>
			///移除所有的孩子结点
			/// </summary>
			/// <param name=""></param>
			/// <returns>移除的孩子结点的数目</returns>
			uint32 removeAllChildren();
			/// <summary>
			/// 将当前的XML数据转换为String
			/// </summary>
			/// <param name=""></param>
			/// <returns>XML字符串</returns>
			String toString() const;

			bool getChildren(const String& childName, XmlElementList& children);

			String getChildValueString(const String& childName);

			bool setChildValueString(const String& name, const String& val);

		private:
			/// <summary>
			///当前结点引用的TiXml结点被删除时的通知函数
			/// </summary>
			/// <param name="pShareXmlElement">正在被删除的TiXml结点</param>
			/// <returns></returns>
			void onShareElementRemove(const TiXmlElement    *pShareXmlElement);
			/// <summary>
			///设置当前结点的共享TiXmlElement
			/// </summary>
			///<param name="pShareXmlElement">共享的TiXml结点</param>
			///<param name="pParentFile"></param>
			/// <returns></returns>
			void shareElement(TiXmlElement    *pShareXmlElement, XmlDocument *pParentFile);

			String convert(const char* pBuf)const;
		private:
			///当前结点所封装的TiXmlElement元素对象
			TiXmlElement   *m_pXmlElement;
			///当前结点以共享模式共享结点数据时，记录父文件对象的指针
			XmlDocument       *m_pParentFile;
		};
	}
}

#endif

